#三种回归算法
import time
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR  # 新增支持向量机回归
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.preprocessing import StandardScaler  # 用于SVR特征缩放

#--------------------------------------------------------------------------数据预处理-----------------------------------------------------------------------------------#
# 加载数据
data = pd.read_excel('task3.xlsx', engine='openpyxl')
#注意表格内不是标准 utf-8 编码，可能是 gbk、gb2312 这类常见中文编码。
print(f"原始数据量: {len(data)} 条")

drop_cols = ['Q1得分', 'Q2得分', 'Q3得分',
             'Q4得分', 'Q5得分', 'Q6得分',
             'Q7得分', 'Q8得分', 'Q9得分',
             'Q10得分', 'Q11得分', 'Q12得分',
             'Q13得分', 'Q14得分', 'Q15得分',
             'Q16得分', 'Q17得分', 'Q18得分']
features = data.drop(columns=drop_cols)

# 手动编码群体协商决策策略
decision_mapping = {
    '未发生意见冲突，双方随机决定答案': 1,
    '未发生意见冲突，一方无记忆完全相信另一方': 2,
    '有意见冲突，双方随机决定答案': 3,
    '有意见冲突，最终选择更确定的人的答案': 4,
    '有意见冲突，最终一方妥协决策': 5,
    '意见一致': 6
}
# 首先按照映射处理，未匹配到的统一标为7
features['群体协商决策策略'] = features['群体协商决策策略'].map(lambda x: decision_mapping.get(x, 7))
# 手动编码会议方式
decision_mapping = {
    '个人单独回忆': 1,
    '小组合作回忆': 2,
}
# 首先按照映射处理，未匹配到的统一标为-1
features['回忆方式'] = features['回忆方式'].map(lambda x: decision_mapping.get(x, -1))
# 定义你要求的映射字典
choice_mapping_task1 = {
    '记忆板块中未涵盖该图像': 0,
    '颂鼎': 1,
    '羊鼎': 2,
    '史鼎': 3,
    '戈鼎': 4,
    '申鼎': 5,
    '口鼎': 6,
    '在': 7,
    '其': 8,
    '见': 9,
    '我': 10,
    '禾': 11,
    '年': 12,
    '屰鼎': 13,
    '大鼎': 14,
    '韦鼎': 15,
    '仔鼎': 16,
    '公鼎': 17,
    '车鼎': 18,
    '疾': 19,
    '学': 20,
    '良': 21,
    '岁': 22,
    '黑': 23,
    '友': 24,
    '素鼎': 25,
    '木鼎': 26,
    '覃鼎': 27,
    '牛鼎': 28,
    '旋鼎': 29,
    '乙鼎': 30,
    '宜': 31,
    '各': 32,
    '酉': 33,
    '吉': 34,
    '既': 35,
    '羌': 36
}

# 批量处理Q1-Q18选择选项
for i in range(1,19):#range(1,12) 只循环到了 Q11选择选项（Q11），
    col = f'Q{i}选择选项'
    features[col] = features[col].map(lambda x: choice_mapping_task1.get(x, -1))  # 没在字典里的，统一归-1

# 删除空值
features = features.dropna()
print(f"去除空值后的数据量: {len(features)} 条")
#--------------------------------------------------------------------------测试集划分与模型应用----------------------------------------------------------------------------------#
# 特征 & 标签
X = features.drop(columns=['总得分'])
y = features['总得分']

# 数据划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 特征标准化（仅用于SVR）
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 模型列表
models = {
    'Linear Regression': LinearRegression(),
    'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42),
    'Support Vector Regression': SVR(kernel='rbf', C=1.0, epsilon=0.1)  # 核函数选择RBF
}

# 存储结果
results = []

# 遍历模型并评估
for name, model in models.items():
    start_time = time.time()
    
    # 区分是否需标准化数据
    if name == 'Support Vector Regression':
        model.fit(X_train_scaled, y_train)
        y_pred = model.predict(X_test_scaled)
    else:
        model.fit(X_train, y_train)
        y_pred = model.predict(X_test)
    
    # 计算指标
    mse = mean_squared_error(y_test, y_pred)
    mae = mean_absolute_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    elapsed_time = time.time() - start_time

    results.append({
        'Model': name,
        'MSE': mse,
        'MAE': mae,
        'R2 Score': r2,
        'Time (s)': round(elapsed_time, 3)
    })

    # 可视化预测效果
    plt.figure(figsize=(6, 5))
    sns.scatterplot(x=y_test, y=y_pred)
    plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--')
    plt.title(f'{name} - Predicted vs Actual')
    plt.xlabel('Actual_Score')
    plt.ylabel('Predicted_Score')
    plt.grid(True)
    plt.tight_layout()
    plt.show()

# 转为DataFrame并展示对比
results_df = pd.DataFrame(results)
print("\n模型性能比较：")
print(results_df.to_markdown(index=False))